////////////////////////////////////////////////////////////////////////////////////////////////////
/// Copyright (c) 2009 - 2010 RacoonStudios
///
/// Permission is hereby granted, free of charge, to any person obtaining a copy of this
/// software and associated documentation files (the "Software"), to deal in the Software
/// without restriction, including without limitation the rights to use, copy, modify, merge,
/// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
/// to whom the Software is furnished to do so, subject to the following conditions:
///
/// The above copyright notice and this permission notice shall be included in all copies or
/// substantial portions of the Software.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
/// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
/// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
/// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
/// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
/// DEALINGS IN THE SOFTWARE.
////////////////////////////////////////////////////////////////////////////////////////////////////

#pragma once
#ifndef filesystem_h__
#define filesystem_h__

#include "core/types.h"
#include "helper/string.h"
#include "helper/array.h"
#include "iosystem/stream.h"
#include "iosystem/filetime.h"

namespace IO
{
	/**--------------------------------------------------------------------------------------------------
	 * \class	FileSystem
	 *
	 * \brief	This is a universal class for a filesystem representation within the
	 *			engine. We will need this class so that we can transform easily the 
	 *			base filesystem class for any platform we want to use.
	 *			Nothing special about it, I just want to have a basic type of filehandler
	 *			which can be specified for every platform.
	 *
	 * \author	khaos
	 * \date	07.12.2009
	 *-----------------------------------------------------------------------------------------------**/
	class FileSystem
	{
		public:

			/**--------------------------------------------------------------------------------------------------
			 * \typedef	void * Handle
			 *
			 * \brief	This represents a file within the engines filesystem.
			 *-----------------------------------------------------------------------------------------------**/
			typedef void * Handle;




			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	static Handle Open(const Helper::String & str, IO::Stream::AccessMode access,
			/// 	IO::Stream::AccessPattern pattern)
			///
			/// \brief	This procedure open the file at the specified path with the specified
			///			parameters you have.
			///
			/// \author	khaos
			/// \date	10.01.2010
			///
			/// \param	[in]	str		The path to the file.
			/// \param	[in]	access	The access type we should have for this file.
			/// \param	[in]	pattern	The access pattern we should have for this file. 
			///
			/// \return	The handle of the file we want to have if available, otherwise NULL.
			////////////////////////////////////////////////////////////////////////////////////////////////////
			static Handle Open(const Helper::String & str, IO::Stream::AccessMode access, IO::Stream::AccessPattern pattern);

			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	static void Close(Handle file)
			///
			/// \brief	This procedure closes the specified file.
			///
			/// \author	khaos
			/// \date	10.01.2010
			///
			/// \param	[in]	file	Handle of the file. 
			////////////////////////////////////////////////////////////////////////////////////////////////////
			static void Close(Handle file);




			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	static void Write(Handle file, const void * buffer, int bytes)
			///
			/// \brief	This procedures writes a specified amount of bytes of a given buffer to
			///			the specified file.
			///
			/// \author	khaos
			/// \date	10.01.2010
			///
			/// \param	[in]	file	The Handle of the file we want to write to.
			/// \param	[in]	buffer	The buffer we want to get our data from.
			/// \param	[in]	bytes	The amount of bytes we want to write to the buffer.
			////////////////////////////////////////////////////////////////////////////////////////////////////
			static void Write(Handle file, const void * buffer, int bytes);

			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	static int Read(Handle file, void * buffer, int bytes)
			///
			/// \brief	This procedure reads a specified amount of bytes from a given file and
			///			will write these in a specified buffer.
			///
			/// \author	khaos
			/// \date	10.01.2010
			///
			/// \param	[in]	file			The Handle of the file we want to read from.
			/// \param	[out]	buffer	The buffer we want to write the read bytes to.
			/// \param	[in]	bytes			The amount of bytes we want to read from the file.
			///
			/// \return	The amount of read bytes.
			////////////////////////////////////////////////////////////////////////////////////////////////////
			static int Read(Handle file, void * buffer, int bytes);

			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	static void Seek(Handle file, int offset, IO::Stream::SeekOrigin origin)
			///
			/// \brief	This procedure searches for a specified offset within a given file.
			///			You can also set the starting position via origin.
			///
			/// \author	khaos
			/// \date	10.01.2010
			///
			/// \param	[in]	file	The Handle of the file we want to search in.
			/// \param	[in]	offset	The offset we are looking for. 
			/// \param	[in]	origin	The starting origin of the search.
			////////////////////////////////////////////////////////////////////////////////////////////////////
			static void Seek(Handle file, int offset, IO::Stream::SeekOrigin origin);

			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	staticint Tell(Handle file)
			///
			/// \brief	This procedure tells us about the topic position we are.
			///
			/// \author	khaos
			/// \date	10.01.2010
			///
			/// \param	[in]	file	The Handle of the file.
			///
			/// \return	The position of the file we are now.
			////////////////////////////////////////////////////////////////////////////////////////////////////
			static int Tell(Handle file);

			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	static void Flush(Handle file)
			///
			/// \brief	Flushes the given file. 
			///
			/// \author	khaos
			/// \date	10.01.2010
			///
			/// \param	[in]	file	The Handle of the file. 
			////////////////////////////////////////////////////////////////////////////////////////////////////
			static void Flush(Handle file);

			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	static bool Eof(Handle file)
			///
			/// \brief	Determines if we have reached the end of the file.
			///
			/// \author	khaos
			/// \date	10.01.2010
			///
			/// \param	[in]	file	The Handle of the file. 
			///
			/// \return	True if the end-of-file is reached, otherwise false.
			////////////////////////////////////////////////////////////////////////////////////////////////////
			static bool Eof(Handle file);

			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	static int GetFileSize(Handle file)
			///
			/// \brief	This procedure returns the size of the specified file.
			///
			/// \author	khaos
			/// \date	10.01.2010
			///
			/// \param	[in]	file	The Handle of the file. 
			///
			/// \return	The size of the specified file.
			////////////////////////////////////////////////////////////////////////////////////////////////////
			static int GetFileSize(Handle file);

			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	static void SetReadOnly(const Helper::String & path, bool readonly)
			///
			/// \brief	This procedure sets the ReadOnly flag of a specified file at the path.
			///
			/// \author	khaos
			/// \date	10.01.2010
			///
			/// \param	[in]	path		Full pathname of the file. 
			/// \param	[in]	readonly	Bool for ReadOnly flag.
			////////////////////////////////////////////////////////////////////////////////////////////////////
			static void SetReadOnly(const Helper::String & path, bool readonly);

			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	static bool IsReadOnly(const Helper::String & path)
			///
			/// \brief	Determines if the specified path has the ReadOnly flag set.
			///
			/// \author	khaos
			/// \date	10.01.2010
			///
			/// \param	[in]	path	Full pathname of the file. 
			///
			/// \return	True if the path is ReadOnly, otherwise false.
			////////////////////////////////////////////////////////////////////////////////////////////////////
			static bool IsReadOnly(const Helper::String & path);

			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	static bool DeleteFile(const Helper::String & path)
			///
			/// \brief	Deletes the file described by path. 
			///
			/// \author	khaos
			/// \date	10.01.2010
			///
			/// \param	[in]	path	Full pathname of the file. 
			///
			/// \return	True if file was successfully deleted, otherwise false.
			////////////////////////////////////////////////////////////////////////////////////////////////////
			static bool DeleteFile(const Helper::String & path);

			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	static bool DeleteDirectory(const Helper::String & path)
			///
			/// \brief	Deletes the directory described by path. 
			///
			/// \author	khaos
			/// \date	10.01.2010
			///
			/// \param	[in]	path	Full pathname of the file. 
			///
			/// \return	True if directory was successfully deleted, otherwise false.
			////////////////////////////////////////////////////////////////////////////////////////////////////
			static bool DeleteDirectory(const Helper::String & path);

			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	static bool FileExists(const Helper::String & path)
			///
			/// \brief	Determines if the specified file at the path exists.
			///
			/// \author	khaos
			/// \date	10.01.2010
			///
			/// \param	[in]	path	Full pathname of the file. 
			///
			/// \return	True if file exists, otherwise false.
			////////////////////////////////////////////////////////////////////////////////////////////////////
			static bool FileExists(const Helper::String & path);

			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	static bool DirectoryExists(const Helper::String & path)
			///
			/// \brief	Determines if the specified directory at the path exists.
			///
			/// \author	khaos
			/// \date	10.01.2010
			///
			/// \param	[in]	path	Full pathname of the directory. 
			///
			/// \return	True if the directory exists, otherwise false. 
			////////////////////////////////////////////////////////////////////////////////////////////////////
			static bool DirectoryExists(const Helper::String & path);

			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	static void SetFileWriteTime(const Helper::String & path, IO::FileTime time)
			///
			/// \brief	This procedure sets the write filetime of the specified fil.e
			///
			/// \author	khaos
			/// \date	10.01.2010
			///
			/// \param	[in]	path	Full pathname of the file. 
			/// \param	[in]	time	The writetime we want the file to have.
			////////////////////////////////////////////////////////////////////////////////////////////////////
			static void SetFileWriteTime(const Helper::String & path, IO::FileTime time);

			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	static IO::FileTime GetFileWriteTime(const Helper::String & path)
			///
			/// \brief	Returns the write filetime of the specified file.
			///
			/// \author	khaos
			/// \date	10.01.2010
			///
			/// \param	[in]	path	Full pathname of the file. 
			///
			/// \return	The file write time. 
			////////////////////////////////////////////////////////////////////////////////////////////////////
			static IO::FileTime GetFileWriteTime(const Helper::String & path);

			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	static bool CreateDirectory(const Helper::String & path)
			///
			/// \brief	Creates a directory. 
			///
			/// \author	khaos
			/// \date	10.01.2010
			///
			/// \param	[in]	path	Full pathname of the file. 
			///
			/// \return	True if directory was successfully created, otherwise false. 
			////////////////////////////////////////////////////////////////////////////////////////////////////
			static bool CreateDirectory(const Helper::String & path);




			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	static Helper::Array<Helper::String> ListFiles(const Helper::String & dirpath,
			/// 	const Helper::String & pattern)
			///
			/// \brief	Returns a list of all files within a specified directory which have the 
			///			specified access patterns.
			///
			/// \author	khaos
			/// \date	10.01.2010
			///
			/// \param	[in]	dirpath	Pathname of the directory. 
			/// \param	[in]	pattern	The access pattern. 
			///
			/// \return	An Array containing all files of the specified directory.
			////////////////////////////////////////////////////////////////////////////////////////////////////
			static Helper::Array<Helper::String> ListFiles(const Helper::String & dirpath, const Helper::String & pattern);

			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	static Helper::Array<Helper::String> ListDirectories(const Helper::String & dirpath,
			/// 	const Helper::String & pattern)
			///
			/// \brief	Returns a list of all directories within a specified directory which
			///			have the specified access pattern
			///
			/// \author	khaos
			/// \date	10.01.2010
			///
			/// \param	[in]	dirpath	Pathname of the directory. 
			/// \param	[in]	pattern	The access pattern. 
			///
			/// \return	An Array containing all directories placed within the specified directory.
			////////////////////////////////////////////////////////////////////////////////////////////////////
			static Helper::Array<Helper::String> ListDirectories(const Helper::String & dirpath, const Helper::String & pattern);






			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	static Helper::String GetUserDirectory()
			///
			/// \brief	Returns the user directory. 
			///			
			///			Under windows this will have a path similar to this:
			///			C:\Users\USERNAME
			///			And under Linux this will have a similar path to this:
			///			./home/USERNAME
			///			Under MacOS I don't know, does anyone tell me?
			///
			/// \author	khaos
			/// \date	10.01.2010
			///
			/// \return	The user directory. 
			////////////////////////////////////////////////////////////////////////////////////////////////////
			static Helper::String GetUserDirectory();

			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	static Helper::String GetAppDataDirectory()
			///
			/// \brief	Returns the application data directory. 
			///
			///			Remember this is some windows specific only!
			///
			/// \author	khaos
			/// \date	10.01.2010
			///
			/// \return	The application data directory. 
			////////////////////////////////////////////////////////////////////////////////////////////////////
			static Helper::String GetAppDataDirectory();

			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	static Helper::String GetTempDirectory()
			///
			/// \brief	Returns the temp directory. 
			///
			///			This is also some windows specified only!
			///
			/// \author	khaos
			/// \date	10.01.2010
			///
			/// \return	The temp directory. 
			////////////////////////////////////////////////////////////////////////////////////////////////////
			static Helper::String GetTempDirectory();

			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	static Helper::String GetHomeDirectory()
			///
			/// \brief	Returns the home directory of the application.
			///
			///			Assumed the application is installed:
			///			Under windows this will be some part as the following:
			///			C:\Program Files(x86)\PROGRAMNAME\
			///
			/// \author	khaos
			/// \date	10.01.2010
			///
			/// \return	The home directory of this application.
			////////////////////////////////////////////////////////////////////////////////////////////////////
			static Helper::String GetHomeDirectory();

			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	static Helper::String GetBinDirectory()
			///
			/// \brief	Returns the bin directory of this application.
			///
			///			This could be different places under different operating systems.
			///
			///			I'm not sure yet which form I will use for the application,
			///			but for now I prefer a form like the following:
			///			Under is will look like this:
			///			GetHomeDirectory()bin\win32\
			///
			///			And under Linux something like this:
			///			GetHomeDirectory()bin\linux\
			///
			///			And under MacOS sometimes, someday when I understand the developer help:
			///			GetHomeDirectory()bin\macos\
			///
			/// \author	khaos
			/// \date	10.01.2010
			///
			/// \return	The bin directory. 
			////////////////////////////////////////////////////////////////////////////////////////////////////
			static Helper::String GetBinDirectory();

			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	static Helper::String GetProgramsDirectory()
			///
			/// \brief	Returns the programs directory. 
			///
			///			Under windows this will be the following path:
			///			C:\Program Files(x86)\
			///
			///			And under linux:
			///			/usr/bin/
			///
			/// \author	khaos
			/// \date	10.01.2010
			///
			/// \return	The programs directory. 
			////////////////////////////////////////////////////////////////////////////////////////////////////
			static Helper::String GetProgramsDirectory();

			

			// WINDOWS ONLY!
			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// \fn	static bool IsDeviceName(const Helper::String & str)
			///
			/// \brief	Determines if the specified str is the filename of the application.
			///
			/// \author	khaos
			/// \date	10.01.2010
			///
			/// \param	[in]	str	The string we want to check.
			///
			/// \return	True if the specified str is the filename, otherwise false.
			////////////////////////////////////////////////////////////////////////////////////////////////////
			static bool IsDeviceName(const Helper::String & str);

		protected:
			
		private:

	};

}

#endif // filesystem_h__